local datatype_integer = {}
local datatype_string = {}
local datatype_hex = {}

function datatype_integer:check(value)
    local tval = tonumber(value)
    if tval then
        return tval >= self.min and tval <= self.max
    end
    return false
end

function datatype_integer:help()
    if self.type == 'int8' or self.type == 'int32' then
        return string.format('integer<%d~%d>', self.min, self.max)
    end
    return string.format('integer<%u~%u>', self.min, self.max)
end

function datatype_string:check(value)
    if type(value) == 'string' then
        local len = string.len(value)
        return len >= self.min and len <= self.max
    end
    return false
end

function datatype_string:help()
    return string.format('string<len:%u~%u>', self.min, self.max)
end

function datatype_hex:check(value)
    if string.match(value, '%x') then
        local tval = tonumber(value)
        return tval ~= nil and tval >= self.min and tval <= self.max
    end
    return false
end

function datatype_hex:help()
    return string.format('hex<%#x~%#x>', self.min, self.max)
end

local datatype = {
    uint8  = function(min, max)
        assert(min == nil or min >= 0)
        assert(max == nil or max >= 0)
        local d = {type = 'uint8', min = min or 0, max = max or 256}
        return setmetatable(d, {__index = datatype_integer})
    end,
    int8   = function(min, max)
        local d = {type = 'int8', min = min or -128, max = max or 127}
        return setmetatable(d, {__index = datatype_integer})
    end,
    uint32 = function(min, max)
        assert(min == nil or min >= 0)
        assert(max == nil or max >= 0)
        local d = {type = 'uint32', min = min or 0, max = max or 4294967295}
        return setmetatable(d, {__index = datatype_integer})
    end,
    int32 = function(min, max)
        local d = {type = 'int32', min = min or -2147483648, max = max or 2147483647}
        return setmetatable(d, {__index = datatype_integer})
    end,
    string = function(min, max)
        local d = {type = 'string', min = min or 1, max = max or 56}
        return setmetatable(d, {__index = datatype_string})
    end,
    hex = function(min, max)
        local d = {type = 'hex', min = min or -2147483648, max = max or 2147483647}
        return setmetatable(d, {__index = datatype_hex})
    end
}

return datatype
